module pcu
(
    input   wire                    pcu_jal_flag_i,
    input   wire                    pcu_jalr_flag_i,
    input   wire                    pcu_branch_flag_i,
    input   wire                    pcu_branch_predic_fault_i,
    //  访存
    input   wire                    pcu_lsu_flag_i,
    input   wire                    pcu_lsu_done_i,
    //  特权指令
    input   wire                    pcu_wfi_flag_i,
    //  异常中断
    input   wire                    pcu_exc_irq_flag_i,
    input   wire                    pcu_mret_flag_i,
    //  来自IDF段的数据相关信号
    input   wire                    pcu_data_raw_depcy_i,

    // output
    output  wire                    pcu_PC_HOLD_o,
    output  wire                    pcu_IFF_IFS_FLUSH_o,
    output  wire                    pcu_IFF_IFS_STALL_o,
    output  wire                    pcu_IFS_IDF_FLUSH_o,
    output  wire                    pcu_IFS_IDF_STALL_o,
    output  wire                    pcu_IDF_IDS_FLUSH_o,
    output  wire                    pcu_IDF_IDS_STALL_o,
    output  wire                    pcu_IDS_EX_FLUSH_o ,
    output  wire                    pcu_IDS_EX_STALL_o ,
    output  wire                    pcu_EX_MEM_FLUSH_o ,
    output  wire                    pcu_EX_MEM_STALL_o ,
    output  wire                    pcu_MEM_WB_FLUSH_o ,
    output  wire                    pcu_MEM_WB_STALL_o
);
    /*
        在PC寄存器中，jal /branch /jalr的 flag优先级要比pc hold的高
        在IFF_IFS段发生跳转（jal branch），且前面流水段发生暂停时，PC仍会跳转，但是IFF_IFS流水线(flush = 0,stall = 1)，所以流水线等于没有跳转
        所以，IFF_IFS输出的指令会一直保持，直到到前面流水段的stall信号消失，此时，pc跳转，IFF_IFS流水线冲刷，完成跳转操作
    */
    assign  pcu_PC_HOLD_o                   =   pcu_IFF_IFS_STALL_o ;     //
//------------------------------------------------------------------------------------------------------
    assign  pcu_IFF_IFS_FLUSH_o             =   (pcu_exc_irq_flag_i  | pcu_mret_flag_i) ? 1'b1
                                                :(
                                                    (pcu_branch_predic_fault_i | pcu_jalr_flag_i) ? 1'b1
                                                    :(
                                                        (pcu_jal_flag_i | pcu_branch_flag_i) ? 1'b1 : 1'b0
                                                    )
                                                ) 
                                                && 
                                                !(pcu_IFS_IDF_STALL_o ) ;
    /* 
        前面的流水段暂停则本级流水段不能冲刷，因为会丢失数据
        又 
        IFF_IFS和IFS_IDF的stall条件相同，为：(pcu_lsu_flag_i && !pcu_lsu_done_i) || (!pcu_exc_irq_flag_i && pcu_wfi_flag_i) || pcu_data_raw_depcy_i;
        IDF_IDS/IDS_EX/EX_MEM的stall条件相同，为：(pcu_lsu_flag_i && !pcu_lsu_done_i) || (!pcu_exc_irq_flag_i && pcu_wfi_flag_i)
        MEM_WB的stall条件为：!pcu_exc_irq_flag_i && pcu_wfi_flag_i
        因此只需判断相邻的前一级是否stall即可
    */
    assign  pcu_IFF_IFS_STALL_o             =   (pcu_lsu_flag_i && !pcu_lsu_done_i) || (!pcu_exc_irq_flag_i && pcu_wfi_flag_i) || pcu_data_raw_depcy_i;//
    //------------------------------------------------------------------------------------------------------
    assign  pcu_IFS_IDF_FLUSH_o             =   (pcu_exc_irq_flag_i  | pcu_mret_flag_i) ? 1'b1
                                                :(
                                                    (pcu_branch_predic_fault_i | pcu_jalr_flag_i) ? 1'b1 :1'b0    
                                                ) 
                                                && 
                                                !(pcu_IDF_IDS_STALL_o);
    assign  pcu_IFS_IDF_STALL_o             =   (pcu_lsu_flag_i && !pcu_lsu_done_i) || (!pcu_exc_irq_flag_i && pcu_wfi_flag_i) || pcu_data_raw_depcy_i;//
//------------------------------------------------------------------------------------------------------
    assign  pcu_IDF_IDS_FLUSH_o             =   (pcu_exc_irq_flag_i  | pcu_mret_flag_i) ? 1'b1
                                                :(
                                                    (pcu_branch_predic_fault_i | pcu_jalr_flag_i) ? 1'b1 : pcu_data_raw_depcy_i
                                                ) 
                                                && 
                                                !(pcu_IDS_EX_STALL_o );
    assign  pcu_IDF_IDS_STALL_o             =   (pcu_lsu_flag_i && !pcu_lsu_done_i) || (!pcu_exc_irq_flag_i && pcu_wfi_flag_i) ;//
    //------------------------------------------------------------------------------------------------------
    assign  pcu_IDS_EX_FLUSH_o              =   (pcu_exc_irq_flag_i  | pcu_mret_flag_i) ? 1'b1
                                                :(
                                                    (pcu_branch_predic_fault_i | pcu_jalr_flag_i) ? 1'b1 : 1'b0
                                                ) 
                                                && 
                                                !(pcu_EX_MEM_STALL_o);
    assign  pcu_IDS_EX_STALL_o              =   (pcu_lsu_flag_i && !pcu_lsu_done_i) || (!pcu_exc_irq_flag_i && pcu_wfi_flag_i);//
    //------------------------------------------------------------------------------------------------------
    assign  pcu_EX_MEM_FLUSH_o              =   (pcu_exc_irq_flag_i  | pcu_mret_flag_i) 
                                                &&
                                                !( pcu_MEM_WB_STALL_o);// 
    assign  pcu_EX_MEM_STALL_o              =   (pcu_lsu_flag_i && !pcu_lsu_done_i) || (!pcu_exc_irq_flag_i && pcu_wfi_flag_i);//
    //------------------------------------------------------------------------------------------------------
    assign  pcu_MEM_WB_FLUSH_o              =   (pcu_lsu_flag_i && !pcu_lsu_done_i) || (pcu_exc_irq_flag_i  | pcu_mret_flag_i);//
    assign  pcu_MEM_WB_STALL_o              =   !pcu_exc_irq_flag_i && pcu_wfi_flag_i;//

endmodule